package cn.com.chengmandian.bike.controller;

import cn.com.chengmandian.bike.dto.WxPayScoreParam;
import cn.com.chengmandian.bike.model.EbMemberPay;
import cn.com.chengmandian.bike.model.EbRefundInfo;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.redis.cache.AgentCacheService;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.com.chengmandian.service.bike.constants.RefundBusinessTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Api(tags = "通知相关接口")
@Slf4j
@RestController
@RequestMapping("/notify")
public class NotifyController {
    @Autowired
    private AgentCacheService agentCacheService;
    @Autowired
    private IEbMemberPayService memberPayService;
    @Autowired
    private IEbRideOrderService rideOrderService;
    @Autowired
    private IEbRefundInfoService refundInfoService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private IEbMemberWalletService memberWalletService;
    @Autowired
    private IEbMemberCardService memberCardService;
    @Autowired
    private IEbMemberComboRecordService memberComboRecordService;
    @Autowired
    private IEbDepositRecordService depositRecordService;
    @Autowired
    private IEbPreOrderService preOrderService;

    @Autowired
    private IEbRidePenaltyService ridePenaltyService;
    /**
     * 微信支付结果通知
     */
    @PostMapping("/wxpay/pay/{agentId}")
    public Map<String, String> wxpayPayNotify(@PathVariable("agentId") String agentId, HttpServletRequest request) {
        try {
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);

            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            log.info("微信支付结果通知:{}", JSONObject.toJSONString(res));
            String payNo = res.getString("out_trade_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:PAY:NOTIFY:" + payNo;
            if (redisService.hasKey(key)) {
                log.info("微信支付结果通知:{} 订单重复响应", payNo);
                throw new BadResponseException("订单重复响应：" + payNo);
            }
            redisService.set(key, payNo, 60 * 10);
            try {
                memberPayService.paySuccessByNo(res.getString("out_trade_no"), res.getString("transaction_id"));
            } catch (Exception e) {
                log.error("支付结果处理异常：{}", JSONObject.toJSONString(res));
                throw e;
            }
        } catch (Exception e) {
            log.error("支付结果通知异常", e);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /**
     * 支付宝支付结果通知
     */
    @PostMapping("/ali/pay/{agentId}")
    public String aliPayNotify(@PathVariable("agentId") String agentId, HttpServletRequest request) {
        try {
            log.info("支付宝异步回调：{}", request.getRequestURI());
            log.info("支付宝异步回调：{}", request.getParameterMap());
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            Map<String, String> res = AliPayUtil.getRequestParam(request, agentInfo.getAliPayPublicCertPath());
            String payNo = res.get("out_trade_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:PAY:NOTIFY:" + payNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("订单重复响应：" + payNo);
            }
            redisService.set(key, payNo, 60 * 10);
            if (res.size() > 0 && ("TRADE_FINISHED".equals(res.get("trade_status")) || "TRADE_SUCCESS".equals(res.get("trade_status")))) {
                try {
                    memberPayService.paySuccessByNo(payNo, res.get("trade_no"));
                } catch (Exception e) {
                    log.error("支付结果处理异常：{}", JSONObject.toJSONString(res));
                    throw e;
                }
            }
        } catch (Exception e) {
            log.error("支付异常!", e);
        }
        return "success";
    }

    /**
     * 微信支付退款通知
     */
    @PostMapping("/wx/refund/{agentId}")
    public Map<String,String> wxRefundNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            String refundNo = res.getString("out_refund_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:NOTIFY:" + refundNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("退款重复响应：" + refundNo);
            }
            refundInfoService.refundSuccess(refundNo, res.getString("refund_id"));
        }catch (Exception ex){
            log.error("微信退款通知异常",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /**
     * 微信支付分退款通知
     * @param agentId
     * @param request
     * @return
     */
    @PostMapping("/wx/pay/score/refund/{agentId}")
    public Map<String,String> wxPayScoreRefundNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            String refundNo = res.getString("out_refund_no");
            log.info("退款通知:{}", JSONObject.toJSONString(res));
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:NOTIFY:" + refundNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("退款重复响应：" + refundNo);
            }
            refundInfoService.refundSuccess(refundNo, res.getString("refund_id"));
        }catch (Exception ex){
            log.error("微信退款通知异常",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }
    /**
     * 微信支付退款通知
     */
    @PostMapping("/wx/wallet/refund/{agentId}")
    public Map<String,String> wxWalletRefundNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            String refundNo = res.getString("out_refund_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:NOTIFY:" + refundNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("退款重复响应：" + refundNo);
            }
            EbRefundInfo ebRefundInfo = refundInfoService.getOne(new LambdaQueryWrapper<EbRefundInfo>()
                    .eq(EbRefundInfo::getRefundNo,refundNo)
                    .last("limit 0,1"));
            Assert.notNull(ebRefundInfo,"退款记录不存在!");
            ebRefundInfo.setChannelNo(res.getString("refund_id"));
            memberWalletService.walletRefundSuccess(ebRefundInfo, res.getString("out_trade_no"));
        }catch (Exception ex){
            log.error("微信退款通知异常",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /**
     * 骑行卡微信支付退款通知
     */
    @PostMapping("/wx/ride/card/refund/{agentId}")
    public Map<String,String> wxRideCardRefundNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            String refundNo = res.getString("out_refund_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:NOTIFY:" + refundNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("退款重复响应：" + refundNo);
            }
            EbRefundInfo ebRefundInfo = refundInfoService.getOne(new LambdaQueryWrapper<EbRefundInfo>()
                    .eq(EbRefundInfo::getRefundNo,refundNo)
                    .last("limit 0,1"));
            Assert.notNull(ebRefundInfo,"退款记录不存在!");
            ebRefundInfo.setChannelNo(res.getString("refund_id"));
            memberCardService.rideCardRefundSuccess(ebRefundInfo, res.getString("out_trade_no"));
        }catch (Exception ex){
            log.error("微信退款通知异常",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /**
     * 骑行卡微信支付退款通知
     */
    @PostMapping("/wx/member/combo/refund/{agentId}")
    public Map<String,String> wxMemberComboRefundNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            String refundNo = res.getString("out_refund_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:NOTIFY:" + refundNo;
            if (redisService.hasKey(key)) {
                throw new BadResponseException("退款重复响应：" + refundNo);
            }
            EbRefundInfo ebRefundInfo = refundInfoService.getOne(new LambdaQueryWrapper<EbRefundInfo>()
                    .eq(EbRefundInfo::getRefundNo,refundNo)
                    .last("limit 0,1"));
            Assert.notNull(ebRefundInfo,"退款记录不存在!");
            ebRefundInfo.setChannelNo(res.getString("refund_id"));
            memberComboRecordService.refundSuccess(ebRefundInfo, res.getString("out_trade_no"));
        }catch (Exception ex){
            log.error("微信退款通知异常",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /**
     * 微信支付分建单通知
     * @param agentId
     * @param request
     * @return
     */
    @PostMapping("/wx/pay/score/create/service/{agentId}")
    public Map<String,String> createServiceOrderNotify(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            log.info("支付分返回结果:"+request);
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            log.info("微信创建支付分结果通知:{}", JSONObject.toJSONString(res));
            String state = res.getString("state");
            String preNo = res.getString("out_order_no");
            String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:CREATE:NOTIFY:" + preNo + ":" + state;
            if (redisService.hasKey(key)) {
                log.info("微信支付结果通知:{} 订单重复响应", preNo);
                throw new BadResponseException("订单重复响应：" + preNo);
            }
            redisService.set(key, preNo, 60 * 10);
            //状态已完成属于完结后自动扣款
            if(state.equals("DONE")){
                JSONObject collection = res.getJSONObject("collection");
                JSONArray arrays = collection.getJSONArray("details");
                List<WxPayScoreParam> list = JSONArray.parseArray(arrays.toJSONString(), WxPayScoreParam.class);
                String transactionId = "";
                for(WxPayScoreParam param:list) {
                    transactionId = param.getTransactionId();
                    log.info("支付交易单号:" + transactionId);
                }
                preOrderService.paySuccessByNo(preNo, transactionId);
            }else{
                preOrderService.addOrderSuccess(preNo, res.getString("order_id"));
            }
        }catch (Exception ex){
            log.error("微信创建支付分结果异常:{}",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    @PostMapping("/wx/isPermissions/{agentId}")
    public Map<String,String> isPermissions(@PathVariable("agentId") String agentId,HttpServletRequest request){
        try{
            AgentInfo agentInfo = agentCacheService.getAgent(agentId);
            LocalMapUtil.setAgentInfo(agentInfo);
            JSONObject res = JSONObject.parseObject(WxPayUtil.parseNotify(request, agentInfo.getWxApiKey3(), agentInfo.getWxPlatformCertPath()));
            log.info("微信支付分预授权结果通知:{}", JSONObject.toJSONString(res));
        }catch (Exception ex){
            log.error("微信支付分预授权结果异常:{}",ex);
        }
        Map<String, String> map = new HashMap<>(12);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }
}
